%{
#include <stdio.h>
#include "util.h"
#include "errormsg.h"

int yylex(void); /* 函数原型 */

void yyerror(char *s)
{
 EM_error(EM_tokPos, "%s", s);
}
%}

%union {
	int pos;
	int ival;
	string sval;
	}

%token <sval> ID STRING
%token <ival> INT

%token 
  COMMA COLON SEMICOLON LPAREN RPAREN LBRACK RBRACK 
  LBRACE RBRACE DOT 
  PLUS MINUS TIMES DIVIDE EQ NEQ LT LE GT GE
  AND OR ASSIGN
  ARRAY IF THEN ELSE WHILE FOR TO DO LET IN END OF 
  BREAK NIL
  FUNCTION VAR TYPE 

%right THEN ASSIGN DO OF        // 解决 条件语句和循环语句末尾exp 的左递归问题
%right ELSE // 解决悬挂else 问题
%left OR
%left AND
%nonassoc EQ NEQ LT LE GT GE
%left PLUS MINUS
%left TIMES DIVIDE
%left UMINUS

%start  program

%%
program : exp
        ;
decs    : decs dec
        | dec
        ;
dec     : tyDec
        | varDec
        | funDec
        ;
tyDec   : TYPE ID EQ ty
        ;
ty      : ID
        | LBRACE tyFields RBRACE
        | ARRAY OF ID
        ;
tyFields: 
        | ID COLON ID
        | tyFields COMMA ID COLON ID
        ;
varDec  : VAR ID ASSIGN exp
        | VAR ID COLON ID ASSIGN exp
        ;
funDec  : FUNCTION ID LPAREN tyFields RPAREN EQ exp
        | FUNCTION ID LPAREN tyFields RPAREN COLON ID EQ exp
        ;
lValue  : ID
        | lValue DOT ID
        | lValue LBRACK exp RBRACK
        ;
exp     : lValue
        | NIL
        | LPAREN RPAREN
        | LPAREN expSeq RPAREN  {/* (exp;exp;...exp) 括号内分号隔开的两个或两个以上表达式组成的序列*/}

        | INT
        | STRING

        | funCall

        | arithExp
        | cmpExp
        | boolExp

        | ID LBRACE RBRACE              {/* 空记录创建 type-id {} */}
        | ID LBRACE records RBRACE      {/* 记录创建 type-id {id=exp{,id=exp}} */}
        | ID LBRACK exp RBRACK OF exp   {/* 数组创建 type-id[exp] of exp */}
        | lValue ASSIGN exp             {/* 赋值无值表达式 */}

        | IF exp THEN exp               {/* if 跳转 */}
        | IF exp THEN exp ELSE exp      {/* if else 跳转，注意 else悬挂问题 */}
        | WHILE exp DO exp              {/* while 循环 */}
        | FOR ID ASSIGN exp TO exp DO exp       {/* for 循环 */}
        | BREAK

        | LET decs IN expSeq END        {/* let decs in expseq end 声明 decs */}
        ;
expSeq  : exp                      {/* exps 是 0个 或更多个用分号分隔的表达式所形成的序列 */}
        | expSeq SEMICOLON exp
        ;
funCall : ID LPAREN RPAREN
        | ID LPAREN expCommaSeq RPAREN
        ;
expCommaSeq     : exp
                | expCommaSeq COMMA exp
                ;
arithExp: MINUS exp     %prec UMINUS
        | exp PLUS exp
        | exp MINUS exp
        | exp TIMES exp
        | exp DIVIDE exp
        ;
cmpExp  : exp EQ exp
        | exp NEQ exp
        | exp GT exp
        | exp LT exp
        | exp GE exp 
        | exp LE exp
        ;
boolExp : exp AND exp
        | exp OR  exp
        ;
records : ID EQ exp                     {/* id=exp{,id=exp} */}
        | records COMMA ID EQ exp
        ;
%%